• Steven Ponce
  • About
  • Data Visualizations
  • Projects
  • Resume
  • Email

On this page

  • Steps to Create this Graphic
    • 1. Load Packages & Setup
    • 2. Read in the Data
    • 3. Examine the Data
    • 4. Tidy Data
    • 5. Visualization Parameters
    • 6. Plot
    • 7. Save
    • 8. Session Info
    • 9. GitHub Repository
    • 10. References

European Basketball Success by Nation

  • Show All Code
  • Hide All Code

  • View Source

Greece dominates with 27 Final Four appearances and 10 titles, nearly double Spain’s performance

TidyTuesday
Data Visualization
R Programming
2025
Analyzing EuroLeague basketball success across nations using faceted bar charts. Greece leads with 27 Final Four appearances and a 37% championship conversion rate.
Published

October 5, 2025

Figure 1: Bar chart comparing EuroLeague basketball success by country. Greece leads with 27 Final Four appearances and 10 titles, followed by Spain (12 appearances, 6 titles) and Turkey (12 appearances, 4 titles). Seven other countries have 1-4 Final Four appearances each. Greece’s 37% title conversion rate is noted.

Steps to Create this Graphic

1. Load Packages & Setup

Show code
```{r}
#| label: load
#| warning: false
#| message: false
#| results: "hide"

## 1. LOAD PACKAGES & SETUP ----
suppressPackageStartupMessages({
if (!require("pacman")) install.packages("pacman")
pacman::p_load(
  tidyverse,   # Easily Install and Load the 'Tidyverse'
  ggtext,      # Improved Text Rendering Support for 'ggplot2'
  showtext,    # Using Fonts More Easily in R Graphs
  janitor,     # Simple Tools for Examining and Cleaning Dirty Data
  scales,      # Scale Functions for Visualization
  glue,        # Interpreted String Literals
  tidytext     # Text Mining using 'dplyr', 'ggplot2', and Other Tidy Tools 
  )})

### |- figure size ----
camcorder::gg_record(
  dir    = here::here("temp_plots"),
  device = "png",
  width  = 8,
  height = 6,
  units  = "in",
  dpi    = 320
)

# Source utility functions
suppressMessages(source(here::here("R/utils/fonts.R")))
source(here::here("R/utils/social_icons.R"))
source(here::here("R/utils/image_utils.R"))
source(here::here("R/themes/base_theme.R"))
```

2. Read in the Data

Show code
```{r}
#| label: read
#| include: true
#| eval: true
#| warning: false

tt <- tidytuesdayR::tt_load(2025, week = 40)

euroleague_basketball <- tt$euroleague_basketball |> clean_names()

tidytuesdayR::readme(tt)
rm(tt)
```

3. Examine the Data

Show code
```{r}
#| label: examine
#| include: true
#| eval: true
#| results: 'hide'
#| warning: false

glimpse(euroleague_basketball)
```

4. Tidy Data

Show code
```{r}
#| label: tidy
#| warning: false

teams_clean <- euroleague_basketball |>
  mutate(
    across(
      c(
        team, home_city, arena, country, last_season,
        years_of_final_four_appearances, years_of_titles_won
      ),
      \(x) if_else(is.na(x), NA_character_, str_squish(x))
    ),
    capacity_num = parse_number(capacity),
    last_season_num = parse_number(last_season),
    final_four_appearances = as.integer(final_four_appearances),
    titles_won = as.integer(titles_won)
  )

# Country aggregation
country_summary <- teams_clean |>
  summarise(
    n_teams = n(),
    tot_titles = sum(titles_won, na.rm = TRUE),
    tot_ff = sum(final_four_appearances, na.rm = TRUE),
    .by = country
  )

# Long df
country_long <- country_summary |>
  filter(tot_ff > 0 | tot_titles > 0) |> # Only show countries with achievements
  mutate(
    # Highlight only Greece 
    highlight = country == "Greece",
    `Final Four apps` = tot_ff,
    Titles = tot_titles
  ) |>
  select(country, highlight, `Final Four apps`, Titles) |>
  pivot_longer(
    cols = c(`Final Four apps`, Titles),
    names_to = "metric",
    values_to = "value"
  ) |>
  mutate(
    country_ordered = reorder_within(country, value, metric)
  )

# Greece's stats
greece_stats <- country_summary |>
  filter(country == "Greece")
```

5. Visualization Parameters

Show code
```{r}
#| label: params
#| include: true
#| warning: false

### |-  plot aesthetics ----
# Get basic theme colors
colors <- get_theme_colors(
  palette = c("TRUE" = "#0066CC", "FALSE" = "gray70")
)

### |- titles and caption ----
title_text <- str_glue("European Basketball Success by Nation")

subtitle_text <- str_glue(
  "Greece dominates with 27 Final Four appearances and 10 titles, nearly double Spain's performance<br>",
  "Shows only countries with Final Four appearances or titles<br>"
)

caption_text <- create_social_caption(
  tt_year = 2025,
  tt_week = 40,
  source_text = "EuroLeague Basketball via Wikipedia"
)

### |-  fonts ----
setup_fonts()
fonts <- get_font_families()

### |-  plot theme ----
# Start with base theme
base_theme <- create_base_theme(colors)

# Add weekly-specific theme elements
weekly_theme <- extend_weekly_theme(
  base_theme,
  theme(
    # Text styling
    plot.title = element_text(face = "bold", family = fonts$title, size = rel(1.4), color = colors$title, margin = margin(b = 10)),
    plot.subtitle = element_text(family = fonts$subtitle, lineheight = 1.2, color = colors$subtitle, size = rel(0.9), margin = margin(b = 20)),

    ## Grid
    panel.grid.major.y = element_blank(),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_line(color = "gray90", linewidth = 0.3),
    
    # Axes
    axis.title = element_text(size = rel(0.9), color = "gray30"),
    axis.text = element_text(color = "gray30"),
    axis.text.y = element_text(size = rel(0.95)),
    axis.ticks = element_blank(),
    
    # Facets
    strip.background = element_rect(fill = "gray95", color = NA),
    strip.text = element_text(
        face = "bold", 
        color = "gray20", 
        size = rel(1),
        margin = margin(t = 8, b = 8)
    ),
    panel.spacing = unit(2, "lines"),
    
    # Legend elements
    legend.position = "plot",
    legend.title = element_text(family = fonts$tsubtitle, color = colors$text, size = rel(0.8), face = "bold"),
    legend.text = element_text(family = fonts$tsubtitle, color = colors$text, size = rel(0.7)),
    legend.margin = margin(t = 15),

    # Plot margin
    plot.margin = margin(20, 20, 20, 20)
  )
)

# Set theme
theme_set(weekly_theme)
```

6. Plot

Show code
```{r}
#| label: plot
#| warning: false

### |- final plot ----
p <- ggplot(country_long, aes(x = value, y = country_ordered)) +
  # Geoms
  geom_col(
    aes(fill = highlight, alpha = highlight),
    width = 0.65
  ) +
  geom_text(
    aes(
      label = if_else(value > 0, as.character(value), ""),
      color = highlight
    ),
    hjust = -0.3,
    size = 3.3,
    fontface = "bold"
  ) +
  geom_text(
    data = tibble(
      metric = "Final Four apps",
      y_pos = 7.8,
      x_pos = 1,
      label = "Greece: 37% conversion rate\n(10 titles from 27 Final Four apps)"
    ),
    aes(x = x_pos, y = y_pos, label = label),
    hjust = 0,
    vjust = 1,
    size = 2.8,
    color = colors$palette[1],
    fontface = "italic",
    lineheight = 0.9,
    inherit.aes = FALSE
  ) +
  # Scales
  scale_y_reordered(expand = expansion(mult = c(0, 0.12))) +
  scale_x_continuous(
    expand = expansion(mult = c(0, 0.18)),
    breaks = pretty_breaks(n = 4)
  ) +
  scale_fill_manual(
    values = colors$palette,
    guide = "none"
  ) +
  scale_alpha_manual(
    values = c("TRUE" = 1, "FALSE" = 0.65),
    guide = "none"
  ) +
  scale_color_manual(
    values = c("TRUE" = "gray20", "FALSE" = "gray50"),
    guide = "none"
  ) +
  # Labs
  labs(
    title = title_text,
    subtitle = subtitle_text,
    caption = caption_text,
    x = NULL,
    y = NULL,
  ) +
  # Facets
  facet_wrap(~metric, nrow = 1, scales = "free") +
  # Theme
  theme(
    plot.title = element_text(
      size = rel(1.8),
      family = fonts$title,
      face = "bold",
      color = colors$title,
      lineheight = 1.1,
      margin = margin(t = 5, b = 5)
    ),
    plot.subtitle = element_markdown(
      size = rel(0.75),
      family = fonts$subtitle,
      color = alpha(colors$subtitle, 0.9),
      lineheight = 1.2,
      margin = margin(t = 5, b = 10)
    ),
    plot.caption = element_markdown(
      size = rel(0.55),
      family = fonts$caption,
      color = colors$caption,
      hjust = 0.5,
      margin = margin(t = 10)
    )
  )
```

7. Save

Show code
```{r}
#| label: save
#| warning: false

### |-  plot image ----  
save_plot(
  plot = p, 
  type = "tidytuesday", 
  year = 2025, 
  week = 40, 
  width  = 8,
  height = 6
  )
```

8. Session Info

Expand for Session Info
R version 4.4.1 (2024-06-14 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 22631)

Matrix products: default


locale:
[1] LC_COLLATE=English_United States.utf8 
[2] LC_CTYPE=English_United States.utf8   
[3] LC_MONETARY=English_United States.utf8
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.utf8    

time zone: America/New_York
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices datasets  utils     methods   base     

other attached packages:
 [1] here_1.0.1      tidytext_0.4.2  glue_1.8.0      scales_1.3.0   
 [5] janitor_2.2.0   showtext_0.9-7  showtextdb_3.0  sysfonts_0.8.9 
 [9] ggtext_0.1.2    lubridate_1.9.3 forcats_1.0.0   stringr_1.5.1  
[13] dplyr_1.1.4     purrr_1.0.2     readr_2.1.5     tidyr_1.3.1    
[17] tibble_3.2.1    ggplot2_3.5.1   tidyverse_2.0.0 pacman_0.5.1   

loaded via a namespace (and not attached):
 [1] gtable_0.3.6       httr2_1.0.6        xfun_0.49          htmlwidgets_1.6.4 
 [5] gh_1.4.1           lattice_0.22-6     tzdb_0.5.0         vctrs_0.6.5       
 [9] tools_4.4.0        generics_0.1.3     parallel_4.4.0     curl_6.0.0        
[13] gifski_1.32.0-1    fansi_1.0.6        janeaustenr_1.0.0  pkgconfig_2.0.3   
[17] tokenizers_0.3.0   Matrix_1.7-0       lifecycle_1.0.4    farver_2.1.2      
[21] compiler_4.4.0     textshaping_0.4.0  munsell_0.5.1      codetools_0.2-20  
[25] snakecase_0.11.1   htmltools_0.5.8.1  SnowballC_0.7.1    yaml_2.3.10       
[29] crayon_1.5.3       pillar_1.9.0       camcorder_0.1.0    magick_2.8.5      
[33] commonmark_1.9.2   tidyselect_1.2.1   digest_0.6.37      stringi_1.8.4     
[37] rsvg_2.6.1         rprojroot_2.0.4    fastmap_1.2.0      grid_4.4.0        
[41] colorspace_2.1-1   cli_3.6.4          magrittr_2.0.3     utf8_1.2.4        
[45] withr_3.0.2        rappdirs_0.3.3     bit64_4.5.2        timechange_0.3.0  
[49] tidytuesdayR_1.1.2 rmarkdown_2.29     gitcreds_0.1.2     bit_4.5.0         
[53] ragg_1.3.3         hms_1.1.3          evaluate_1.0.1     knitr_1.49        
[57] markdown_1.13      rlang_1.1.6        gridtext_0.1.5     Rcpp_1.0.13-1     
[61] xml2_1.3.6         renv_1.0.3         vroom_1.6.5        svglite_2.1.3     
[65] rstudioapi_0.17.1  jsonlite_1.8.9     R6_2.5.1           systemfonts_1.1.0 

9. GitHub Repository

Expand for GitHub Repo

The complete code for this analysis is available in tt_2025_40.qmd.

For the full repository, click here.

10. References

Expand for References
  1. Data Sources:
  • TidyTuesday 2025 Week 40: [EuroLeague Basketball](https://github.com/rfordatascience/tidytuesday/blob/main/data/2025/2025-10-07
Back to top
Source Code
---
title: "European Basketball Success by Nation"
subtitle: "Greece dominates with 27 Final Four appearances and 10 titles, nearly double Spain's performance"
description: "Analyzing EuroLeague basketball success across nations using faceted bar charts. Greece leads with 27 Final Four appearances and a 37% championship conversion rate."
date: "2025-10-05" 
categories: ["TidyTuesday", "Data Visualization", "R Programming", "2025"]
tags: [
  "EuroLeague",
  "basketball",
  "sports analytics",
  "ggplot2",
  "tidytext",
  "faceted visualization",
  "reorder_within",
  "data cleaning",
  "consulting-style charts",
  "Europe"
]
image: "thumbnails/tt_2025_40.png"
format:
  html:
    toc: true
    toc-depth: 5
    code-link: true
    code-fold: true
    code-tools: true
    code-summary: "Show code"
    self-contained: true
    theme: 
      light: [flatly, assets/styling/custom_styles.scss]
      dark: [darkly, assets/styling/custom_styles_dark.scss]
editor_options: 
  chunk_output_type: inline
execute: 
  freeze: true                                    
  cache: true                                       
  error: false
  message: false
  warning: false
  eval: true
---

![Bar chart comparing EuroLeague basketball success by country. Greece leads with 27 Final Four appearances and 10 titles, followed by Spain (12 appearances, 6 titles) and Turkey (12 appearances, 4 titles). Seven other countries have 1-4 Final Four appearances each. Greece's 37% title conversion rate is noted.](tt_2025_40.png){#fig-1}

### <mark> **Steps to Create this Graphic** </mark>

#### 1. Load Packages & Setup

```{r}
#| label: load
#| warning: false
#| message: false      
#| results: "hide"     

## 1. LOAD PACKAGES & SETUP ----
suppressPackageStartupMessages({
if (!require("pacman")) install.packages("pacman")
pacman::p_load(
  tidyverse,   # Easily Install and Load the 'Tidyverse'
  ggtext,      # Improved Text Rendering Support for 'ggplot2'
  showtext,    # Using Fonts More Easily in R Graphs
  janitor,     # Simple Tools for Examining and Cleaning Dirty Data
  scales,      # Scale Functions for Visualization
  glue,        # Interpreted String Literals
  tidytext     # Text Mining using 'dplyr', 'ggplot2', and Other Tidy Tools 
  )})

### |- figure size ----
camcorder::gg_record(
  dir    = here::here("temp_plots"),
  device = "png",
  width  = 8,
  height = 6,
  units  = "in",
  dpi    = 320
)

# Source utility functions
suppressMessages(source(here::here("R/utils/fonts.R")))
source(here::here("R/utils/social_icons.R"))
source(here::here("R/utils/image_utils.R"))
source(here::here("R/themes/base_theme.R"))
```

#### 2. Read in the Data

```{r}
#| label: read
#| include: true
#| eval: true
#| warning: false

tt <- tidytuesdayR::tt_load(2025, week = 40)

euroleague_basketball <- tt$euroleague_basketball |> clean_names()

tidytuesdayR::readme(tt)
rm(tt)
```

#### 3. Examine the Data

```{r}
#| label: examine
#| include: true
#| eval: true
#| results: 'hide'
#| warning: false

glimpse(euroleague_basketball)
```

#### 4. Tidy Data

```{r}
#| label: tidy
#| warning: false

teams_clean <- euroleague_basketball |>
  mutate(
    across(
      c(
        team, home_city, arena, country, last_season,
        years_of_final_four_appearances, years_of_titles_won
      ),
      \(x) if_else(is.na(x), NA_character_, str_squish(x))
    ),
    capacity_num = parse_number(capacity),
    last_season_num = parse_number(last_season),
    final_four_appearances = as.integer(final_four_appearances),
    titles_won = as.integer(titles_won)
  )

# Country aggregation
country_summary <- teams_clean |>
  summarise(
    n_teams = n(),
    tot_titles = sum(titles_won, na.rm = TRUE),
    tot_ff = sum(final_four_appearances, na.rm = TRUE),
    .by = country
  )

# Long df
country_long <- country_summary |>
  filter(tot_ff > 0 | tot_titles > 0) |> # Only show countries with achievements
  mutate(
    # Highlight only Greece 
    highlight = country == "Greece",
    `Final Four apps` = tot_ff,
    Titles = tot_titles
  ) |>
  select(country, highlight, `Final Four apps`, Titles) |>
  pivot_longer(
    cols = c(`Final Four apps`, Titles),
    names_to = "metric",
    values_to = "value"
  ) |>
  mutate(
    country_ordered = reorder_within(country, value, metric)
  )

# Greece's stats
greece_stats <- country_summary |>
  filter(country == "Greece")
```

#### 5. Visualization Parameters

```{r}
#| label: params
#| include: true
#| warning: false

### |-  plot aesthetics ----
# Get basic theme colors
colors <- get_theme_colors(
  palette = c("TRUE" = "#0066CC", "FALSE" = "gray70")
)

### |- titles and caption ----
title_text <- str_glue("European Basketball Success by Nation")

subtitle_text <- str_glue(
  "Greece dominates with 27 Final Four appearances and 10 titles, nearly double Spain's performance<br>",
  "Shows only countries with Final Four appearances or titles<br>"
)

caption_text <- create_social_caption(
  tt_year = 2025,
  tt_week = 40,
  source_text = "EuroLeague Basketball via Wikipedia"
)

### |-  fonts ----
setup_fonts()
fonts <- get_font_families()

### |-  plot theme ----
# Start with base theme
base_theme <- create_base_theme(colors)

# Add weekly-specific theme elements
weekly_theme <- extend_weekly_theme(
  base_theme,
  theme(
    # Text styling
    plot.title = element_text(face = "bold", family = fonts$title, size = rel(1.4), color = colors$title, margin = margin(b = 10)),
    plot.subtitle = element_text(family = fonts$subtitle, lineheight = 1.2, color = colors$subtitle, size = rel(0.9), margin = margin(b = 20)),

    ## Grid
    panel.grid.major.y = element_blank(),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_line(color = "gray90", linewidth = 0.3),
    
    # Axes
    axis.title = element_text(size = rel(0.9), color = "gray30"),
    axis.text = element_text(color = "gray30"),
    axis.text.y = element_text(size = rel(0.95)),
    axis.ticks = element_blank(),
    
    # Facets
    strip.background = element_rect(fill = "gray95", color = NA),
    strip.text = element_text(
        face = "bold", 
        color = "gray20", 
        size = rel(1),
        margin = margin(t = 8, b = 8)
    ),
    panel.spacing = unit(2, "lines"),
    
    # Legend elements
    legend.position = "plot",
    legend.title = element_text(family = fonts$tsubtitle, color = colors$text, size = rel(0.8), face = "bold"),
    legend.text = element_text(family = fonts$tsubtitle, color = colors$text, size = rel(0.7)),
    legend.margin = margin(t = 15),

    # Plot margin
    plot.margin = margin(20, 20, 20, 20)
  )
)

# Set theme
theme_set(weekly_theme)
```

#### 6. Plot

```{r}
#| label: plot
#| warning: false

### |- final plot ----
p <- ggplot(country_long, aes(x = value, y = country_ordered)) +
  # Geoms
  geom_col(
    aes(fill = highlight, alpha = highlight),
    width = 0.65
  ) +
  geom_text(
    aes(
      label = if_else(value > 0, as.character(value), ""),
      color = highlight
    ),
    hjust = -0.3,
    size = 3.3,
    fontface = "bold"
  ) +
  geom_text(
    data = tibble(
      metric = "Final Four apps",
      y_pos = 7.8,
      x_pos = 1,
      label = "Greece: 37% conversion rate\n(10 titles from 27 Final Four apps)"
    ),
    aes(x = x_pos, y = y_pos, label = label),
    hjust = 0,
    vjust = 1,
    size = 2.8,
    color = colors$palette[1],
    fontface = "italic",
    lineheight = 0.9,
    inherit.aes = FALSE
  ) +
  # Scales
  scale_y_reordered(expand = expansion(mult = c(0, 0.12))) +
  scale_x_continuous(
    expand = expansion(mult = c(0, 0.18)),
    breaks = pretty_breaks(n = 4)
  ) +
  scale_fill_manual(
    values = colors$palette,
    guide = "none"
  ) +
  scale_alpha_manual(
    values = c("TRUE" = 1, "FALSE" = 0.65),
    guide = "none"
  ) +
  scale_color_manual(
    values = c("TRUE" = "gray20", "FALSE" = "gray50"),
    guide = "none"
  ) +
  # Labs
  labs(
    title = title_text,
    subtitle = subtitle_text,
    caption = caption_text,
    x = NULL,
    y = NULL,
  ) +
  # Facets
  facet_wrap(~metric, nrow = 1, scales = "free") +
  # Theme
  theme(
    plot.title = element_text(
      size = rel(1.8),
      family = fonts$title,
      face = "bold",
      color = colors$title,
      lineheight = 1.1,
      margin = margin(t = 5, b = 5)
    ),
    plot.subtitle = element_markdown(
      size = rel(0.75),
      family = fonts$subtitle,
      color = alpha(colors$subtitle, 0.9),
      lineheight = 1.2,
      margin = margin(t = 5, b = 10)
    ),
    plot.caption = element_markdown(
      size = rel(0.55),
      family = fonts$caption,
      color = colors$caption,
      hjust = 0.5,
      margin = margin(t = 10)
    )
  )
```

#### 7. Save

```{r}
#| label: save
#| warning: false

### |-  plot image ----  
save_plot(
  plot = p, 
  type = "tidytuesday", 
  year = 2025, 
  week = 40, 
  width  = 8,
  height = 6
  )
```

#### 8. Session Info

::: {.callout-tip collapse="true"}
##### Expand for Session Info

```{r, echo = FALSE}
#| eval: true
#| warning: false

sessionInfo()
```
:::

#### 9. GitHub Repository

::: {.callout-tip collapse="true"}
##### Expand for GitHub Repo

The complete code for this analysis is available in [`tt_2025_40.qmd`](https://github.com/poncest/personal-website/blob/master/data_visualizations/TidyTuesday/2025/tt_2025_40.qmd).

For the full repository, [click here](https://github.com/poncest/personal-website/).
:::

#### 10. References

::: {.callout-tip collapse="true"}
##### Expand for References

1.  Data Sources:

-   TidyTuesday 2025 Week 40: \[EuroLeague Basketball\](https://github.com/rfordatascience/tidytuesday/blob/main/data/2025/2025-10-07
:::

© 2024 Steven Ponce

Source Issues